/*
 *    Copyright (c) 2018-2025, lengleng All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the following disclaimer.
 * Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution.
 * Neither the name of the robot4cloud.com developer nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 * Author: lengleng (wangiegie@gmail.com)
 */

package com.hitqz.robot.daemon.quartz.controller;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.google.common.cache.Cache;
import com.google.common.collect.Lists;
import com.hitqz.robot.api.business.dto.RobotClientSummaryDto;
import com.hitqz.robot.api.business.entity.GoodsBuffersEntity;
import com.hitqz.robot.api.business.entity.RobotEntity;
import com.hitqz.robot.api.business.entity.RobotJobEntity;
import com.hitqz.robot.api.dispatch.protocol.dto.FormConfigModalDto;
import com.hitqz.robot.api.dispatch.protocol.dto.FormFieldConfigModalDto;
import com.hitqz.robot.api.dispatch.protocol.dto.RobotNextStepDto;
import com.hitqz.robot.biz.service.GoodsBuffersService;
import com.hitqz.robot.biz.service.RobotJobService;
import com.hitqz.robot.biz.service.RobotService;
import com.hitqz.robot.common.core.util.R;
import com.hitqz.robot.daemon.quartz.dao.AgvDao;
import com.hitqz.robot.daemon.quartz.entity.SysJob;
import com.hitqz.robot.daemon.quartz.model.*;
import com.hitqz.robot.daemon.quartz.service.SysJobService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.quartz.SchedulerException;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;

import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * @author guoliang
 * @date 2024-3-26 11:19:18
 * <p>
 * 定时任务管理
 */
@RestController
@RequiredArgsConstructor
@RequestMapping("")
@Tag(description = "sys-job", name = "agv")
@Slf4j
public class AgvController {

	private final AgvDao agvDao;

	private final RobotJobService robotJobService;

	private final SysJobService sysJobService;

	private final RestTemplate restTemplate;

	private final RobotService robotService;

	private final GoodsBuffersService goodsBuffersService;


	// 等待通知接口为 /agv/arriveResponse
	// 任务流程： 轮对。 轮对左/右(911008/911007)  轮对校验取前置点(911016) 等待通知 然后前往(911009) 放下后到达 轮对校验取前置点(911016) 通知 缓存完成

	/**
	 *   报废-缓存: 前往报废架前置点(911004)，等待通知下一步报废架(911015)，前往报废架前置点(911004),通知取完成，到达缓存架(911017), 通知放完成（带上位置）
	 *   报废-下线: 前往报废架前置点(911014)，等待通知下一步报废架(911005)，前往报废架前置点(911004),通知取完成，到达报废架下线(911020),等待操作完成离开
	 *   返修-缓存: 前往报废架前置点(911015)，等待通知下一步返修架(911006)，前往报废架前置点(911006),通知取完成，到达缓存架(911017), 通知放完成（带上位置）
	 *。 返修-上线: 前往报废架前置点(911015)，等待通知下一步返修架(911006)，前往报废架前置点(911006),通知取完成，上线前置点(911013), 等待通知，前往(911012), 上线前置点(911013),通知放完成（带上位置）
	 *。 新轴-上线: 前往新轴前置点(91118)，等待通知下一步新轴(91101)，前往新轴前置点(91118),通知取完成，上线前置点(911013), 等待通知，前往(911012), 上线前置点(911013),通知放完成
	 *。 旧轴-上线: 前往新轴前置点(91102)，等待通知下一步新轴(91119)，前往新轴前置点(91102),通知取完成，上线前置点(911013), 等待通知，前往(911012), 上线前置点(911013),通知放完成
	 //*   新/旧-上线: 前往报废架前置点(911015)，等待通知下一步返修架(911006)，前往报废架前置点(911006),通知取完成，上线前置点(911013), 等待通知，前往(911012), 上线前置点(911013),通知放完成（带上位置）
	 * @param agvCallRequestParams
	 * @return
	 * @throws SchedulerException
	 */


//	Version:0.9 StartHTML:0000000105 EndHTML:0000001800 StartFragment:0000000141 EndFragment:0000001764
//	{
//  "srcnum" : 4,
//  "des" : "911017",
//  "data" : [ { } ],
//  "src" : "91102",
//  "srcplace" : 7396,
//  "zx" : "03"
//	}
//  {"data":[{"pj_id":"LZ0091120241100218","zh":"11111","zx":"81"}],"des":"911009","src":"911008","srcnum":1,"srcplace":9}
	@PostMapping(value = "/agv/call")
	@Schema(description = "AGV请求任务")
	public AgvCallResult call(@RequestBody AgvCallRequestParams agvCallRequestParams) throws SchedulerException {
		log.info("Calling agv: {}", JSONObject.toJSONString(agvCallRequestParams));
		String src = agvCallRequestParams.getSrc();
		String dest = agvCallRequestParams.getDes();
		Integer num = agvCallRequestParams.getSrcnum();
		List<AgvCallDataDto> data = agvCallRequestParams.getData();
		List<AgvCallDataDto> newData = Lists.newArrayList();
		log.info("接受到任务: {}---{}", src , dest);
		RobotJobEntity robotJob =  new RobotJobEntity();
		robotJob.setCron("0 * * * * ?");
		robotJob.setName("上位机呼叫，时间" + DateUtil.format(new Date(), "yyyy-MM-dd HH:mm:ss"));
		if (agvCallRequestParams.getData() != null) {
			robotJob.setRemark(JSONObject.toJSONString(agvCallRequestParams.getData()));
		}
		robotJob.setGroupId(6);
		String content ="{\"robotSn\":\"sr_002\",\"id\":null,\"formTitle\":\"运输工单上下文参数配置\",\"formName\":\"tickets_params_agv\",\"fields\":[{\"id\":45,\"name\":\"targetPosCode\",\"label\":\"目标点位编码\",\"type\":\"radio\",\"defaultValue\":null,\"currentValue\":\"LM34\",\"required\":true,\"min\":null,\"max\":null,\"pattern\":null,\"options\":[\"{\\\"label\\\":\\\"LM34\\\",\\\"value\\\":\\\"LM34\\\"}\"]},{\"id\":46,\"name\":\"sourcePosCode\",\"label\":\"起始点位编码\",\"type\":\"radio\",\"defaultValue\":null,\"currentValue\":\"LM23\",\"required\":true,\"min\":null,\"max\":null,\"pattern\":null,\"options\":[\"{\\\"label\\\":\\\"LM23\\\",\\\"value\\\":\\\"LM23\\\"}\"]}]}";
		content = content.replaceAll("LM34", dest).replaceAll("LM23", src);
		String zx = agvCallRequestParams.getZx();
		if (StrUtil.isNotBlank(zx)) {
			log.info("zx is required");
			LambdaQueryWrapper<GoodsBuffersEntity> wrapper = Wrappers.lambdaQuery();
			wrapper.eq(GoodsBuffersEntity::getStoreName, zx);
			int max = 4;
			if (src.contains("911017")) {
				// 起点是缓存区
				wrapper.eq(GoodsBuffersEntity::getStoreStatus, 1);
				List<GoodsBuffersEntity> goodsBuffersEntities = goodsBuffersService.list(wrapper
						.orderByAsc(GoodsBuffersEntity::getSn)
				);
				log.info("GoodsBuffersEntity:" + goodsBuffersEntities.size());
				if (num > goodsBuffersEntities.size()) {
					log.info("缓存区没有缓存可以取");
					return AgvCallResult.builder()
							.ret(false)
							.build();
				}
				// 查询起点
				CollectionUtil.reverse(goodsBuffersEntities);
				GoodsBuffersEntity goodsBuffersEntity = goodsBuffersEntities.get(0);
				content = content.replaceAll(src, goodsBuffersEntity.getBindPosName());
				if (CollectionUtil.isNotEmpty(data) && data.size() > 0) {
					for (int i = 0; i < num; i++) {
						AgvCallDataDto agvCallDataDto = data.get(i);
						agvCallDataDto.setPos(goodsBuffersEntities.get(i).getName());
						newData.add(agvCallDataDto);
					}
				}
				content = content.replaceAll(src, goodsBuffersEntity.getBindPosName());
			} else if (dest.contains("911017") ) {
				// 终点是缓存区
				wrapper.eq(GoodsBuffersEntity::getStoreStatus, 0);
				List<GoodsBuffersEntity> goodsBuffersEntities = goodsBuffersService.list(wrapper.orderByAsc(GoodsBuffersEntity::getSn));
				if (num > goodsBuffersEntities.size()) {
					log.info("缓存区没有缓存可以放");
					return AgvCallResult.builder()
							.ret(false)
							.build();
				}
				GoodsBuffersEntity goodsBuffersEntity = goodsBuffersEntities.get(0);
				content = content.replaceAll(dest, goodsBuffersEntity.getBindPosName());
				if (CollectionUtil.isNotEmpty(data)  && data.size() > 0) {
					for (int i = 0; i < num; i++) {
						AgvCallDataDto agvCallDataDto = data.get(i);
						agvCallDataDto.setPos(goodsBuffersEntities.get(i).getName());
						newData.add(agvCallDataDto);
					}
				}

				content = content.replaceAll(dest, goodsBuffersEntity.getBindPosName());
			}
		} else {
			newData = agvCallRequestParams.getData();
		}
		FormConfigModalDto jsonArray = JSONObject.parseObject(content, FormConfigModalDto.class);
		List<FormFieldConfigModalDto> formFieldConfigModalDtos = jsonArray.getFields();
		FormFieldConfigModalDto dto = new FormFieldConfigModalDto();

		dto = new FormFieldConfigModalDto();
		dto.setLabel("srcnum");
		dto.setName("srcnum");
		dto.setCurrentValue("" + agvCallRequestParams.getSrcnum());
		formFieldConfigModalDtos.add(dto);

		dto = new FormFieldConfigModalDto();
		dto.setLabel("pjData");
		dto.setName("pjData");
		dto.setCurrentValue(JSONObject.toJSONString(newData));
		formFieldConfigModalDtos.add(dto);


		jsonArray.setFields(formFieldConfigModalDtos);
		robotJob.setContent(JSONObject.toJSONString(jsonArray));
		robotJobService.save(robotJob);



		SysJob sysJob = sysJobService.addJobByRobotJob(robotJob.getName(), robotJob.getCron(), String.valueOf(robotJob.getId()));
		if (sysJob  != null) {
			sysJobService.runOneJob(sysJob.getJobId());
		}
		// 等待
		try {
			TimeUnit.SECONDS.sleep(2);
		}catch (Exception e) {
		}
		// 工单查询

		Cache<Integer, RobotEntity> executeRobot = SpringUtil.getBean("executeTaskRobot");
		RobotEntity robotEntity = executeRobot.getIfPresent(robotJob.getId());
		if (robotEntity == null) {
			return AgvCallResult.builder()
					.ret(false)
					.build();
		}

		return AgvCallResult.builder()
				.ret(true)
				.sbID(robotEntity.getRobotSn()).build();
	}


	public static void main(String[] args) throws Exception {
		String content ="{\"robotSn\":\"sr_002\",\"id\":null,\"formTitle\":\"运输工单上下文参数配置\",\"formName\":\"tickets_params_agv\",\"fields\":[{\"id\":45,\"name\":\"targetPosCode\",\"label\":\"目标点位编码\",\"type\":\"radio\",\"defaultValue\":null,\"currentValue\":\"LM34\",\"required\":true,\"min\":null,\"max\":null,\"pattern\":null,\"options\":[\"{\\\"label\\\":\\\"LM34\\\",\\\"value\\\":\\\"LM34\\\"}\"]},{\"id\":46,\"name\":\"sourcePosCode\",\"label\":\"起始点位编码\",\"type\":\"radio\",\"defaultValue\":null,\"currentValue\":\"LM23\",\"required\":true,\"min\":null,\"max\":null,\"pattern\":null,\"options\":[\"{\\\"label\\\":\\\"LM23\\\",\\\"value\\\":\\\"LM23\\\"}\"]}]}";
		//content = content.replaceAll("LM34", dest).replaceAll("LM23", src);
		FormConfigModalDto jsonArray = JSONObject.parseObject(content, FormConfigModalDto.class);



	}


	@PostMapping(value = "/agv/arriveResponse")
	public AgvCallResult arriveResponse(@RequestBody AgvArriveResponseParams agvArriveResponseParams) {
		log.info("arriveResponse: {}", JSONObject.toJSONString(agvArriveResponseParams));
		RobotNextStepDto robotNextStepDto = new RobotNextStepDto();
		robotNextStepDto.setClientId(agvArriveResponseParams.getSbID());
		SpringUtil.getApplicationContext().publishEvent(robotNextStepDto);
		return AgvCallResult.builder()
				.ret(true).sbID(agvArriveResponseParams.getSbID()).build();
	}

	@PostMapping(value = "/agv/pick")
	@Deprecated
	public AgvCallResult pick(@RequestBody AgvPickParams agvPickParams) {
		AgvCallResult agvCallResult = agvDao.pick(agvPickParams);
		log.info("pick: {}", agvCallResult.toString());
		HttpHeaders headers = new HttpHeaders();
		headers.setContentType(MediaType.valueOf("application/json;UTF-8"));
		JSONObject jsonObject = new JSONObject();
		jsonObject.put("faultPos", "911013");
		jsonObject.put("src", "911013");
		jsonObject.put("desc", "911013");
		jsonObject.put("sbID", "sr_agv1");
		jsonObject.put("problem", "急停按钮触发");

		HttpEntity<String> strEntity = new HttpEntity<String>(jsonObject.toString(), headers);
		String result = restTemplate.postForObject("", strEntity, String.class);



		return AgvCallResult.builder()
				.ret(true).sbID("sr_agv1").build();
	}

	@PostMapping(value = "/agv/store")
	@Deprecated
	public AgvCallResult store(@RequestBody AgvStoreParams agvStoreParams) {
		AgvCallResult agvCallResult = agvDao.store(agvStoreParams);
		log.info("store: {}", agvCallResult.toString());
		return AgvCallResult.builder()
				.ret(true).sbID("sr_agv1").build();
	}


	@PostMapping(value = "/scx/start")
	@Deprecated
	public AgvCallResult start(@RequestBody ScxStatus status) {
		return AgvCallResult.builder()
				.ret(true).sbID("sr_agv1").build();
	}

	@PostMapping(value = "/scx/stop")
	@Deprecated
	public AgvCallResult stop(@RequestBody ScxStatus status) {
		return AgvCallResult.builder()
				.ret(true).sbID("sr_agv1").build();
	}


	@PostMapping(value = "/agv/fault")
	@Deprecated
	public AgvCallResult fault() {
		RestTemplate restTemplate = new RestTemplate();
		HttpHeaders headers = new HttpHeaders();
		headers.setContentType(MediaType.valueOf("application/json;UTF-8"));
		JSONObject jsonObject = new JSONObject();
		jsonObject.put("faultPos", "911013");
		jsonObject.put("src", "911013");
		jsonObject.put("desc", "911013");
		jsonObject.put("sbID", "sr_agv1");
		jsonObject.put("problem", "急停按钮触发");

		HttpEntity<String> strEntity = new HttpEntity<String>(jsonObject.toString(), headers);
		String result = restTemplate.postForObject("http://276to9673ki4.vicp.fun/api/v1/centreApp/agv/fault/", strEntity, String.class);

		//AgvFaultParams agvFaultParams = new AgvFaultParams();
		//agvFaultParams.setFaultPos("91119");
		//agvFaultParams.setSrc("91119");
		//agvFaultParams.setDesc("91119");
		//agvFaultParams.setSbID("sr_agv1");
		//agvFaultParams.setProblem("急停触发");
		//agvDao.fault(agvFaultParams);


		return AgvCallResult.builder()
				.ret(true).sbID("sr_agv1").build();
	}



	@PostMapping(value = "/agv/arrive")
	@Deprecated
	public AgvCallResult arrive(@RequestBody AgvArriveResponseParams agvArriveResponseParams) {
		RestTemplate restTemplate = new RestTemplate();
		HttpHeaders headers = new HttpHeaders();
		headers.setContentType(MediaType.valueOf("application/json;UTF-8"));
		JSONObject jsonObject = new JSONObject();
		jsonObject.put("sbID", agvArriveResponseParams.getSbID());
		jsonObject.put("fktime", DateUtil.format(new Date(), "yyyy-MM-dd HH:mm:ss"));
		jsonObject.put("arrivePos", "91119");
		HttpEntity<String> strEntity = new HttpEntity<String>(jsonObject.toString(), headers);
		String result = restTemplate.postForObject("http://276to9673ki4.vicp.fun/api/v1/centreApp/agv/arrive/",
				strEntity, String.class);
		return AgvCallResult.builder()
				.ret(true).sbID("sr_agv1").build();
	}


	@PostMapping(value = "/agv/workMode")
	@Deprecated
	public AgvCallResult workMode(@RequestBody AgvWorkModeParams workModeParams) {
		AgvCallResult agvCallResult = agvDao.workmode(workModeParams);
		log.info("work: {}", agvCallResult.toString());
		return AgvCallResult.builder()
				.ret(true).sbID("sr_agv1").build();
	}
	@PostMapping(value = "/agv/powerOn")
	@Deprecated
	public AgvCallResult powerOn(@RequestBody PowerRobotParams powerRobotParams) {
		RestTemplate restTemplate = new RestTemplate();
		HttpHeaders headers = new HttpHeaders();
		headers.setContentType(MediaType.valueOf("application/json;UTF-8"));
		JSONObject jsonObject = new JSONObject();
		jsonObject.put("sbID", "sr_agv1");
		jsonObject.put("fktime", DateUtil.format(new Date(), "yyyy-MM-dd HH:mm:ss"));

		HttpEntity<String> strEntity = new HttpEntity<String>(jsonObject.toString(), headers);
		String result = restTemplate.postForObject("http://276to9673ki4.vicp.fun/api/v1/incomeDecomposeApp/agv/poweron", strEntity, String.class);


		//CallAgvResult agvCallResult = agvDao.powerOn(powerRobotParams);
		//log.info("work: {}", agvCallResult.toString());
		return AgvCallResult.builder()
				.ret(true).sbID("sr_agv1").build();
	}

	@PostMapping(value = "/agv/powerOff")
	@Deprecated
	public AgvCallResult powerOff(@RequestBody PowerRobotParams powerRobotParams) {
		CallAgvResult agvCallResult = agvDao.powerOff(powerRobotParams);
		log.info("work: {}", agvCallResult.toString());
		return AgvCallResult.builder()
				.ret(true).sbID("sr_agv1").build();
	}


	@GetMapping(value = "/agv/currentPos")
	@Operation(summary = "获取AGV当前坐标状态")
	public R<List<RobotPosDto>> currentPos() {
		// 清除错误、 重定位、 订单清除、 急停、 调度上下线(清除控制权)
		List<RobotPosDto> list = Lists.newArrayList();
		List<RobotEntity> robotEntities = robotService.list();
		Cache<String, RobotClientSummaryDto> posInfoDtoCache = SpringUtil.getBean("robotCache");
		for (RobotEntity robotEntity : robotEntities) {
			RobotClientSummaryDto posInfoDto = posInfoDtoCache.getIfPresent(robotEntity.getRobotSn());
			RobotPosDto robotPosDto = new RobotPosDto();
			if (posInfoDto != null) {
				robotPosDto.setPosX(String.valueOf(posInfoDto.getPosition().getLaserPos().getX()));
				robotPosDto.setPosY(String.valueOf(posInfoDto.getPosition().getLaserPos().getY()));
				robotPosDto.setYaw(String.valueOf(posInfoDto.getPosition().getLaserPos().getYaw()));
				robotPosDto.setAgvName(posInfoDto.getStatus().getName());
				robotPosDto.setAgvSn(posInfoDto.getStatus().getSn());
				robotPosDto.setOnlineState(posInfoDto.getStatus().getOnlineStatusStr());
				robotPosDto.setRunningState(posInfoDto.getStatus().getWorkStatusStr());
				robotPosDto.setAlarmState("");
			} else {
				robotPosDto.setPosX("0");
				robotPosDto.setPosY("0");
				robotPosDto.setYaw("0");
				robotPosDto.setAgvName(robotEntity.getRobotName());
				robotPosDto.setAgvSn(robotEntity.getRobotSn());
				robotPosDto.setOnlineState("离线");
				robotPosDto.setRunningState("空闲");
				robotPosDto.setAlarmState("");
			}
			list.add(robotPosDto);
		}
		return R.ok(list);
	}

	@GetMapping(value = "/agv/storeBuffersStatus")
	@Operation(summary = "缓存架状态")
	public R<List<StoreStatusDto>> storeBuffersStatus() {
		List<StoreStatusDto> list = Lists.newArrayList();
		LambdaQueryWrapper<GoodsBuffersEntity> wrapper = Wrappers.lambdaQuery();
		List<GoodsBuffersEntity> goodsBuffersEntities = goodsBuffersService.list(
				wrapper.orderByAsc(GoodsBuffersEntity::getName)
						.orderByAsc(GoodsBuffersEntity::getSn)
		);
		for (GoodsBuffersEntity goodsBuffersEntity : goodsBuffersEntities) {
			StoreStatusDto storeStatusDto = new StoreStatusDto();
			BeanUtil.copyProperties(goodsBuffersEntity, storeStatusDto);
			storeStatusDto.setStoreStatusStr(storeStatusDto.getStoreStatus() == 1 ? "已存放":"未存放");
			list.add(storeStatusDto);
		}
		return R.ok(list);
	}

	/**
	 * 对轮 172.24.3.241
	 *     172.24.3.242
	 * @return
	 */

	@GetMapping(value = "/agv/gateStatus")
	@Operation(summary = "道闸状态")
	public R<List<GateStatusDto>> gateStatus() {
		List<GateStatusDto> list = Lists.newArrayList();
		GateStatusDto dto = new GateStatusDto();
		dto.setIp("172.24.3.241");
		dto.setStatus(1);
		list.add(dto);
		dto = new GateStatusDto();
		dto.setIp("172.24.3.242");
		dto.setStatus(0);
		list.add(dto);
		return R.ok(list);
	}


}
